home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 001 / tmodem23.arc / TM1.INC < prev    next >
Encoding:
Text File  |  1985-05-19  |  34.4 KB  |  1,078 lines

  1. (****************************************************************************)
  2. (*                         EN-QUE SERIAL PORT INPUT &                       *)
  3. (*                         DE-QUE SERIAL PORT OUTPUT                        *)
  4. (*                             INTERRUPT DRIVEN                             *)
  5. (****************************************************************************)
  6.    procedure
  7.       async_intr_handler;
  8.    begin
  9.       inline ($FB/$50/$53/$51/$52/$57/$56/$06/$1E);
  10.       inline ($2E/$A1/datasegment
  11.              /$8E/$D8);
  12.       int_ident := port[int_ident_reg];
  13.       repeat
  14.          if int_ident = 4 then begin
  15.             line_status := port[line_status_reg] and $1C;
  16.             sin_buffer_ptr^[sin_store_ptr] := port[base_com_addr];
  17.             if line_status = 0 then begin
  18.                if ascii_mode then begin
  19.                   if sin_buffer_ptr^[sin_store_ptr]=XOFF then
  20.                      port[int_enable_reg] := 1;
  21.                   if sin_buffer_ptr^[sin_store_ptr]=XON  then
  22.                      port[int_enable_reg] := 3;
  23.                end;
  24.                if sin_store_ptr = sin_buf_size then
  25.                   sin_store_ptr := 1
  26.                else
  27.                   sin_store_ptr := sin_store_ptr + 1;
  28.                sin_buf_fill_cnt := sin_buf_fill_cnt + 1;
  29.             end;
  30.          end
  31.          else begin
  32.             if sout_store_ptr = sout_read_ptr then begin
  33.                port[int_enable_reg] := 1;
  34.                sout_int_off := true;
  35.             end
  36.             else begin
  37.                port[base_com_addr] := sout_buffer_ptr^[sout_read_ptr];
  38.                if sout_read_ptr = sout_buf_size then
  39.                   sout_read_ptr := 1
  40.                else
  41.                   sout_read_ptr := sout_read_ptr + 1;
  42.             end;
  43.          end;
  44.          int_ident := port[int_ident_reg];
  45.       until int_ident = 1;
  46.       port[$20] := $20;
  47.       inline ($1F/$07/$5E/$5F/$5A/$59/$5B/$58/$5D/$5D/$CF);
  48.    end;
  49.  
  50. (****************************************************************************)
  51. (*                       EN-QUE SERIAL PORT OUTPUT                          *)
  52. (****************************************************************************)
  53.    procedure
  54.       store_sout_buffer(ch : char);
  55.    var
  56.       new_sout_store_ptr   : integer;
  57.       cnt                  : integer;
  58.    begin
  59.       if sout_store_ptr = sout_buf_size then
  60.          new_sout_store_ptr := 1
  61.       else
  62.          new_sout_store_ptr := sout_store_ptr + 1;
  63.       cnt := 0;
  64.       while new_sout_store_ptr = sout_read_ptr do begin  { Wait for room }
  65.          cnt := cnt + 1;                                 { in the queue. }
  66.          if cnt > 40 then begin
  67.             sout_store_ptr := sout_read_ptr;
  68.             continue_transfer := false;
  69.             sout_int_off := true;
  70.             exit;
  71.          end;
  72.          delay( wait_increment );
  73.       end;
  74.       sout_buffer_ptr^[sout_store_ptr] := ord(ch);
  75.       sout_store_ptr := new_sout_store_ptr;
  76.       if sout_int_off then begin
  77.          sout_int_off := false;
  78.          port[int_enable_reg] := 3;
  79.       end;
  80.    end;
  81.  
  82. (****************************************************************************)
  83. (*                        DE-QUE SERIAL PORT INPUT                          *)
  84. (****************************************************************************)
  85.    function
  86.       read_sin_buffer : char;
  87.    begin
  88.       read_sin_buffer := chr(sin_buffer_ptr^[sin_read_ptr]);
  89.       if sin_read_ptr = sin_buf_size then
  90.          sin_read_ptr := 1
  91.       else
  92.          sin_read_ptr := sin_read_ptr + 1;
  93.       sin_buf_fill_cnt := sin_buf_fill_cnt - 1;
  94.       if sin_xoff then begin
  95.          if sin_buf_fill_cnt < sin_buf_drain_lim then begin
  96.             sin_xoff := false;
  97.             store_sout_buffer( chr(xon) );
  98.          end;
  99.       end
  100.       else begin
  101.          if sin_buf_fill_cnt > sin_buf_fill_lim then begin
  102.             sin_xoff := true;
  103.             store_sout_buffer( chr(xoff) );
  104.          end;
  105.       end;
  106.    end;
  107.  
  108. (****************************************************************************)
  109. (*                           SETUP SERIAL PORT                              *)
  110. (****************************************************************************)
  111.    procedure
  112.       setserial(baudrate,stopbits,databits,parity : integer);
  113.    var
  114.       parameter : integer;
  115.       parn      : byte;
  116.    begin
  117.       case baudrate of
  118.          300  : begin
  119.                    baudrate:=2;
  120.                    sync_time := wait_increment div 4;
  121.                 end;
  122.          1200 : begin
  123.                    baudrate:=4;
  124.                    sync_time := wait_increment div 11;
  125.                 end;
  126.          2400 : begin
  127.                    baudrate:=5;
  128.                    sync_time := wait_increment div 22;
  129.                 end;
  130.          4800 : begin
  131.                    baudrate:=6;
  132.                    sync_time := (wait_increment div 44)+1;
  133.                 end;
  134.          9600 : begin
  135.                    baudrate:=7;
  136.                    sync_time := (wait_increment div 88)+1;
  137.                 end;
  138.       else
  139.          baudrate:=4;                     { Default to 1200 baud }
  140.          sync_time := wait_increment div 11;
  141.       end;
  142.       if stopbits=2 then
  143.          stopbits:=1
  144.       else
  145.          stopbits:=0;                     { Default to 1 stop bit }
  146.       parn := parity;
  147.       if databits=7 then
  148.          databits:=2
  149.       else begin
  150.          databits:=3;                     { Default to 8 data bits }
  151.          parn:=0;
  152.       end;
  153.       parameter:=(baudrate shl 5)+(stopbits shl 2)+databits;
  154.       case parn of
  155.          1 : parameter:=parameter+24;
  156.          2 : parameter:=parameter+8;
  157.       end;
  158.       regs.DX := 0;                       { 0 = COM1;   1 = COM2 }
  159.       regs.AX := parameter;
  160.       regs.FLAGS := 0;
  161.       intr($14,regs);
  162.       port[modem_control_reg] := $0B;
  163.       port[$21] := port[$21] and turn_IRQ_on;
  164.       port[int_enable_reg] := 1;
  165.       sout_int_off := true;
  166.    end;
  167.  
  168. (****************************************************************************)
  169. (*                         DISPLAY PROMPTS LINE                             *)
  170. (****************************************************************************)
  171.    procedure
  172.       clear_pos( i,j : integer );
  173.    begin
  174.       escape_win;
  175.       textcolor( BGcolor );
  176.       textbackground( FGcolor );
  177.       gotoxy(i,j);
  178.       write(' ');
  179.       textcolor( FGcolor );
  180.       textbackground( BGcolor );
  181.       reset_win;
  182.    end;
  183.  
  184.    procedure
  185.       display_prompts;
  186.    begin
  187.       escape_win;
  188.       textcolor( BGcolor );
  189.       textbackground( FGcolor );
  190.       gotoxy(1,25);
  191.       clreol;
  192.       write('   Alt: T=Terminate, R=Receive, X=Transmit, C=Capture, H=Help, S=Chg Params.   ');
  193.       textcolor( FGcolor );
  194.       textbackground( BGcolor );
  195.       reset_win;
  196.    end;
  197.  
  198. (****************************************************************************)
  199. (*                         SAVE CAPTURE BUFFERS                             *)
  200. (****************************************************************************)
  201.    procedure
  202.       save_capture_buffers;
  203.    var
  204.       r        : real;
  205.    begin
  206.       writeln;
  207.       write(' Enter Filename for Capture Buffer Save: ');
  208.       readln(filename);
  209.       if length(filename)=0 then exit;
  210.       assign(recv_file,filename);
  211.       rewrite(recv_file);
  212.       capture_curr := capture_first;
  213.       repeat
  214.          if capture_curr^.capture_store_ptr <= capture_buf_size then
  215.             capture_curr^.capture_buffer[capture_curr^.capture_store_ptr] := ^Z
  216.          else
  217.             capture_curr^.capture_store_ptr := capture_buf_size;
  218.          if capture_curr^.capture_store_ptr > 1 then begin
  219.             r := (capture_curr^.capture_store_ptr / 128.0) + 0.999;
  220.             blockwrite(recv_file,capture_curr^.capture_buffer,trunc(r));
  221.          end;
  222.          capture_curr := capture_curr^.capture_next;
  223.       until capture_curr = nil;
  224.       close(recv_file);
  225.    end;
  226.  
  227. (****************************************************************************)
  228. (*                      ENTER / LEAVE  CAPTURE MODE                         *)
  229. (****************************************************************************)
  230.    procedure
  231.       toggle_capture_mode;
  232.    begin
  233.       if capture_flag then begin
  234.          capture_flag := false;
  235.          mkwin(11,8,67,14,'Exit Capture Mode');
  236.          writeln;
  237.          write(' Do you wish to save capture buffer? ');
  238.          readln(yes_no);
  239.          yes_no := upcase(yes_no[1]);
  240.          if yes_no = 'Y' then
  241.             save_capture_buffers;
  242.          capture_curr := capture_first;
  243.          repeat
  244.             capture_first := capture_curr;
  245.             capture_curr := capture_curr^.capture_next;
  246.             dispose(capture_first);
  247.          until capture_curr = nil;
  248.          rmwin;
  249.          clear_pos(1,25);
  250.       end
  251.       else begin
  252.          capture_flag := true;
  253.          capture_warning := false;
  254.          escape_win;
  255.          gotoxy(1,25);
  256.          write('*');
  257.          reset_win;
  258.          new(capture_first);
  259.          capture_curr := capture_first;
  260.          capture_curr^.capture_store_ptr := 1;
  261.          capture_curr^.capture_next := nil;
  262.       end;
  263.    end;
  264.  
  265. (****************************************************************************)
  266. (*                          CAPTURE A CHARACTER                             *)
  267. (****************************************************************************)
  268.    procedure
  269.       capture( c : char );
  270.    begin
  271.       capture_curr^.capture_buffer[capture_curr^.capture_store_ptr] := c;
  272.       capture_curr^.capture_store_ptr := capture_curr^.capture_store_ptr + 1;
  273.       if capture_curr^.capture_store_ptr > capture_buf_size then begin
  274.          if memory < 6 then
  275.             toggle_capture_mode
  276.          else begin
  277.             new(capture_curr^.capture_next);
  278.             capture_curr := capture_curr^.capture_next;
  279.             capture_curr^.capture_store_ptr := 1;
  280.             capture_curr^.capture_next := nil;
  281.             if (not capture_warning and (memory < 10)) then begin
  282.                capture_warning := true;
  283.                escape_win;
  284.                gotoxy(1,25);
  285.                write('W');
  286.                reset_win;
  287.             end;
  288.          end;
  289.       end;
  290.    end;
  291.  
  292. (****************************************************************************)
  293. (*                             PROCESS ESCAPE                               *)
  294. (****************************************************************************)
  295.    procedure
  296.       prt_cap( c : char );
  297.    begin
  298.       if printer_on then write(lst,c);
  299.       if capture_flag then capture( c );
  300.    end;
  301.  
  302.    procedure
  303.       horz_tab;
  304.    var
  305.       i,j  : byte;
  306.    begin
  307.       i := 8 - (wherex mod 8);
  308.       for j:=1 to i do begin
  309.          write( ' ' );
  310.          prt_cap( ' ' );
  311.       end;
  312.    end;
  313.  
  314.    procedure
  315.       wrt( var c : char );
  316.    var
  317.       i  : integer;
  318.    begin
  319.       i := ord( c );
  320.       if ( i > 95 ) and line_drawing_chars then
  321.          c := char(alt_character[i]);
  322.       case c of
  323.          NUL : exit;
  324.          FF  : clrscr;
  325.          TAB : begin
  326.                   horz_tab;
  327.                   exit;
  328.                end;
  329.       else
  330.          write( c );
  331.       end;
  332.       prt_cap( c );
  333.    end;
  334.  
  335.    procedure
  336.       set_graphics;
  337.    var
  338.       i     : integer;
  339.    begin
  340.       for i:=1 to escape_number do begin
  341.          case escape_register[i] of
  342.             0 : begin
  343.                    white_shade := lightgray;
  344.                    FG := white_shade;
  345.                    BG := black;
  346.                 end;
  347.             1 : begin
  348.                    white_shade := white;
  349.                    FG := white_shade;
  350.                 end;
  351.             4 : FG := blue;
  352.             5 : FG := FG + blink;
  353.             7 : begin
  354.                    FG := BGcolor;
  355.                    BG := FGcolor;
  356.                 end;
  357.             8 : FG := BG;
  358.            30 : FG := black;
  359.            31 : FG := red;
  360.            32 : FG := green;
  361.            33 : FG := yellow;
  362.            34 : FG := blue;
  363.            35 : FG := magenta;
  364.            36 : FG := cyan;
  365.            37 : FG := white_shade;
  366.            40 : BG := black;
  367.            41 : BG := red;
  368.            42 : BG := green;
  369.            43 : BG := yellow;
  370.            44 : BG := blue;
  371.            45 : BG := magenta;
  372.            46 : BG := cyan;
  373.            47 : BG := white_shade;
  374.          end;
  375.       end;
  376.       textcolor( FG );
  377.       textbackground( BG );
  378.    end;
  379.  
  380.    procedure
  381.       addr_cursor;
  382.    begin
  383.       if escape_number=1       then escape_register[2]:=1;
  384.       if escape_register[1]=0  then escape_register[1]:=1;
  385.       if escape_register[1]=25 then escape_register[1]:=24;
  386.       gotoxy(escape_register[2],escape_register[1]);
  387.    end;
  388.  
  389.    procedure
  390.       cursor_up;
  391.    var
  392.       my  : integer;
  393.    begin
  394.       if escape_register[1]=0 then escape_register[1]:=1;
  395.       my := wherey - escape_register[1];
  396.       gotoxy(wherex,my);
  397.    end;
  398.  
  399.    procedure
  400.       cursor_down;
  401.    var
  402.       my  : integer;
  403.    begin
  404.       if escape_register[1]=0 then escape_register[1]:=1;
  405.       my := wherey + escape_register[1];
  406.       if my > 24 then my:=24;
  407.       gotoxy(wherex,my);
  408.    end;
  409.  
  410.    procedure
  411.       cursor_right;
  412.    var
  413.       mx  : integer;
  414.    begin
  415.       if escape_register[1]=0 then escape_register[1]:=1;
  416.       mx := wherex + escape_register[1];
  417.       if mx > 80 then mx:=80;
  418.       gotoxy(mx,wherey);
  419.    end;
  420.  
  421.    procedure
  422.       cursor_left;
  423.    var
  424.       mx  : integer;
  425.    begin
  426.       if escape_register[1]=0 then escape_register[1]:=1;
  427.       mx := wherex - escape_register[1];
  428.       gotoxy(mx,wherey);
  429.    end;
  430.  
  431.    procedure
  432.       clear_scr;
  433.    begin
  434.       if escape_register[1] = 2 then clrscr;
  435.    end;
  436.  
  437.    procedure
  438.       clear_line;
  439.    begin
  440.       if escape_register[1] = 0 then clreol;
  441.    end;
  442.  
  443.    procedure
  444.       escape_wrt;
  445.    var
  446.       i   : integer;
  447.    begin
  448.       for i:=1 to length( escape_str ) do
  449.          wrt( escape_str[i] );
  450.    end;
  451.  
  452.    procedure
  453.       process_escape( c : char );
  454.    label
  455.       MORE_ESCAPE;
  456.    var
  457.       ch   : char;
  458.    begin
  459.       case c of
  460.          '[','(' : begin
  461.                       escape_type := c;
  462.                       exit;
  463.                    end;
  464.          'm'     : set_graphics;
  465.          'f','H' : addr_cursor;
  466.          'A'     : begin
  467.                       if vt100_mode[1]='F' then goto MORE_ESCAPE;
  468.                       cursor_up;
  469.                    end;
  470.          'B'     : begin
  471.                       if escape_type = '(' then
  472.                          line_drawing_chars := false
  473.                       else begin
  474.                          if vt100_mode[1]='F' then goto MORE_ESCAPE;
  475.                          cursor_down;
  476.                       end;
  477.                    end;
  478.          'C'     : begin
  479.                       if vt100_mode[1]='F' then goto MORE_ESCAPE;
  480.                       cursor_right;
  481.                    end;
  482.          'D'     : begin
  483.                       if vt100_mode[1]='F' then goto MORE_ESCAPE;
  484.                       cursor_left;
  485.                    end;
  486.          '0'     : begin
  487.                       if escape_type <> '(' then goto MORE_ESCAPE;
  488.                       line_drawing_chars := true;
  489.                    end;
  490.          'J'     : clear_scr;
  491.          'K'     : clear_line;
  492.          ^N      : play( escape_str + ' ' );
  493.          ' '     : exit;
  494.       else
  495.          goto MORE_ESCAPE;
  496.       end;
  497.       escape_mode := false;
  498.       exit;
  499.    MORE_ESCAPE:
  500.       ch := upcase( c );
  501.       escape_str := escape_str + ch;
  502.       if ch in [ 'A'..'G','L'..'P' ] then exit;
  503.       if ch in [ '0'..'9' ] then begin
  504.          escape_register[escape_number] := (escape_register[escape_number] * 10) + ord( ch ) - ord( '0' );
  505.          exit;
  506.       end;
  507.       case ch of
  508.          ';', ',' : begin
  509.                        escape_number := escape_number + 1;
  510.                        escape_register[escape_number] := 0;
  511.                     end;
  512.          'T', 'S', '#', '+', '-', '>', '<', '.'
  513.                   : ;
  514.       else
  515.          escape_mode := false;
  516.          escape_wrt;
  517.       end;
  518.    end;
  519.  
  520. (****************************************************************************)
  521. (*                             SCREEN HANDLER                               *)
  522. (****************************************************************************)
  523.    procedure
  524.       scrwrite( var c : char );
  525.    begin
  526.       if monitor_mode then begin
  527.          if c < ' ' then begin
  528.             prt_cap( '^' );
  529.             prt_cap( chr( ord( c ) + 64 ) );
  530.          end
  531.          else
  532.             prt_cap( c );
  533.          write( c );
  534.       end
  535.       else begin
  536.          if c = ESC then begin
  537.             if escape_mode then escape_wrt;
  538.             escape_str := '';
  539.             escape_number := 1;
  540.             escape_register[1] := 0;
  541.             escape_mode := true;
  542.          end
  543.          else
  544.             if escape_mode then
  545.                process_escape( c )
  546.             else
  547.                wrt( c );
  548.       end;
  549.    end;
  550.  
  551. (****************************************************************************)
  552. (*                       COMMUNICATIONS PROBLEMS !!!                        *)
  553. (****************************************************************************)
  554.    procedure
  555.       ask_operator(var ch : char);
  556.    begin
  557.       mkwin(60,18,80,22,'');
  558.       error_count := 0;
  559.       writeln;
  560.       write(' Continue? y/n ');
  561.       readln(yes_no);
  562.       yes_no := upcase(yes_no[1]);
  563.       if yes_no[1] = 'Y' then
  564.          ch := NAK
  565.       else begin
  566.          ch := CAN;
  567.          continue_transfer := false;
  568.       end;
  569.       rmwin;
  570.    end;
  571.  
  572. (****************************************************************************)
  573. (*                              SEND BLOCK                                  *)
  574. (****************************************************************************)
  575.    procedure
  576.       xmit_data(data_block : strtype);
  577.    var
  578.       i         : integer;
  579.    begin
  580.       i := 0;
  581.       while ( i < length(data_block) ) and continue_transfer do begin
  582.          i := i+1;
  583.          store_sout_buffer(data_block[i]);
  584.          if keypressed then begin
  585.             read(kbd,kbd_char);
  586.             ask_operator(kbd_char);
  587.          end;
  588.       end;
  589.       sin_read_ptr := sin_store_ptr;         { Flush the buffer. }
  590.    end;
  591.  
  592. (****************************************************************************)
  593. (*                             RECEIVE BLOCK                                *)
  594. (****************************************************************************)
  595.    procedure
  596.       recv_data(var data_block : strtype; char_cnt : integer);
  597.    var
  598.       cnt      : integer;
  599.       time     : integer;
  600.       max_loop : byte;
  601.    begin
  602.       data_block := '';
  603.       cnt := 0;
  604.       time := wait_increment;
  605.       max_loop := 40;
  606.       repeat
  607.          if cnt > 0 then
  608.             delay(time);
  609.          if sin_store_ptr <> sin_read_ptr then begin
  610.             data_block := data_block + read_sin_buffer;
  611.             cnt := 0;
  612.             time := sync_time;
  613.             max_loop := 5;
  614.          end
  615.          else
  616.             cnt := cnt + 1;
  617.          if keypressed then begin
  618.             read(kbd,kbd_char);
  619.             ask_operator(kbd_char);
  620.          end;
  621.       until ( cnt > max_loop )
  622.          or ( char_cnt = length(data_block) )
  623.          or ( not continue_transfer );
  624.    end;
  625.  
  626. (****************************************************************************)
  627. (*                             SYNC WITH REMOTE                             *)
  628. (****************************************************************************)
  629.    procedure
  630.       sync_with_remote;
  631.    begin
  632.       sout_read_ptr := sout_store_ptr;
  633.       delay(sync_time);
  634.       while sin_read_ptr <> sin_store_ptr do begin
  635.          sin_read_ptr := sin_store_ptr;
  636.          delay(sync_time);
  637.          delay(sync_time);
  638.       end;
  639.    end;
  640.    procedure
  641.       sync_NAK;
  642.    var
  643.       i   : integer;
  644.    begin
  645.       for i:=1 to 20 do sync_with_remote;
  646.    end;
  647.  
  648. (****************************************************************************)
  649. (*                       PROCESS XMODEM INPUT BUFFER                        *)
  650. (****************************************************************************)
  651.    procedure
  652.       process_xmodem_buffer(var xbuf : strtype; var resp : char);
  653.    label
  654.       SEND_NAK;
  655.    var
  656.       i      : integer;
  657.       chk    : integer;
  658.       xcnt   : integer;
  659.    begin
  660.       if length(xbuf) <> 132 then
  661.          goto SEND_NAK;
  662.       if xbuf[1] <> SOH then
  663.          goto SEND_NAK;
  664.       if (ord(xbuf[2]) <> ( ord(xbuf[3]) xor $FF) ) then
  665.          goto SEND_NAK;
  666.       if lo(block_count) = ord(xbuf[2]) then begin
  667.          resp := ACK;
  668.          exit;
  669.       end;
  670.       if lo(block_count + 1) <> ord(xbuf[2]) then
  671.          goto SEND_NAK;
  672.       chk := 0;
  673.       xcnt := xmodem_buf_cnt + 1;
  674.       for i:=4 to 131 do begin
  675.          chk := chk + ord(xbuf[i]);
  676.          xmodem_table_ptr^[xcnt,i-3] := xbuf[i];
  677.       end;
  678.       if lo(chk) <> ord(xbuf[132]) then
  679.          goto SEND_NAK;
  680.       block_count := block_count + 1;
  681.       xmodem_buf_cnt := xmodem_buf_cnt + 1;
  682.       if xmodem_buf_cnt = max_xmodem_buffers then begin
  683.          blockwrite(recv_file,xmodem_table_ptr^,max_xmodem_buffers);
  684.          xmodem_buf_cnt := 0;
  685.       end;
  686.       resp := ACK;
  687.       exit;
  688.    SEND_NAK:
  689.       error_count := error_count + 1;
  690.       if error_count > 30 then
  691.          ask_operator(resp)
  692.       else
  693.          resp := NAK;
  694.       sync_NAK;
  695.    end;
  696.  
  697. (****************************************************************************)
  698. (*                             RECEIVE FILE                                 *)
  699. (****************************************************************************)
  700.    procedure
  701.       display_headings;
  702.    begin
  703.       clreol;
  704.       writeln;
  705.       writeln('    Block Count    Error Count     Time');
  706.       writeln('    -----------    -----------   --------');
  707.    end;
  708.    procedure
  709.       display_counts( y : integer );
  710.    begin
  711.       curr_time := time;
  712.       gotoxy(8,y);
  713.       write(block_count:4);
  714.       gotoxy(24,y);
  715.       write(error_count:2);
  716.       gotoxy(34,y);
  717.       curr_time := time;
  718.       writeln(delta_time(start_time,curr_time));
  719.    end;
  720.    procedure
  721.       receive_file;
  722.    var
  723.       buf          : strtype;
  724.       response     : char;
  725.    begin
  726.       xmodem_buf_cnt := 0;
  727.       error_count := 0;
  728.       block_count := 0;
  729.       continue_transfer := true;
  730.       mkwin(15,4,62,12,'Receive XMODEM');
  731.       write(' Enter Filename to Receive: ');
  732.       readln(filename);
  733.       if length(filename)=0 then begin
  734.          rmwin;
  735.          exit;
  736.       end;
  737.       setserial(baud,stopbits,8,0);
  738.       assign(recv_file,filename);
  739.       rewrite(recv_file);
  740.       display_headings;
  741.       start_time := time + ' ';
  742.       sync_with_remote;
  743.       store_sout_buffer( NAK );        { NAK the sender to start things off. }
  744.       recv_data(buf,132);              { Get the 1st block from sender.      }
  745.       while ( buf <> CAN )
  746.         and ( buf <> EOT )
  747.         and ( continue_transfer )
  748.       do begin
  749.          process_xmodem_buffer(buf,response);
  750.          if continue_transfer then begin
  751.             display_counts( 5 );
  752.             sync_with_remote;
  753.             store_sout_buffer( response );
  754.             recv_data(buf,132);
  755.          end;
  756.       end;
  757.       sync_with_remote;
  758.       if not continue_transfer then begin
  759.          store_sout_buffer( CAN );
  760.          buf := CAN;
  761.       end;
  762.       if xmodem_buf_cnt > 0 then
  763.          blockwrite(recv_file,xmodem_table_ptr^,xmodem_buf_cnt);
  764.       close(recv_file);
  765.       setserial(baud,stopbits,databits,par);
  766.       if buf = CAN then
  767.          writeln(' File transfer canceled!')
  768.       else begin
  769.          store_sout_buffer( ACK );
  770.          writeln(' File transfer complete.');
  771.       end;
  772.       wait_for_key;
  773.       rmwin;
  774.    end;
  775.  
  776. (****************************************************************************)
  777. (*                            ALLOCATE BUFFERS                              *)
  778. (****************************************************************************)
  779.    procedure
  780.       get_buffer( var final : boolean );
  781.    begin
  782.       if xmodem_buf_cnt = 0 then begin
  783.          xmodem_rd := 1;
  784.          while ( xmodem_buf_cnt < max_xmodem_buffers ) and ( xmodem_rd <> 0 )
  785.          do begin
  786.             xmodem_buf_cnt := xmodem_buf_cnt + 1;
  787.             blockread(xmit_file,xmodem_table_ptr^[xmodem_buf_cnt],1,xmodem_rd);
  788.          end;
  789.          xmodem_ptr := 0;
  790.       end;
  791.       xmodem_ptr := xmodem_ptr + 1;
  792.       xmodem_buf_cnt := xmodem_buf_cnt - 1;
  793.       if ( xmodem_buf_cnt = 0 ) and ( xmodem_rd = 0 ) then
  794.          final := true
  795.       else
  796.          final := false;
  797.    end;
  798.  
  799. (****************************************************************************)
  800. (*                    FORMAT XMODEM OUTPUT BUFFER                           *)
  801. (****************************************************************************)
  802.    procedure
  803.       build_xmodem_buffer(var xbuf : strtype; var last_block : boolean);
  804.    var
  805.       i       : integer;
  806.       chk     : integer;
  807.       ch      : char;
  808.    begin
  809.       get_buffer( last_block );
  810.       xbuf := SOH + chr(lo(block_count)) + chr(lo(block_count) xor $FF);
  811.       chk := 0;
  812.       for i:=1 to 128 do begin
  813.          ch := xmodem_table_ptr^[xmodem_ptr,i];
  814.          xbuf := xbuf + ch;
  815.          chk := chk + ord( ch );
  816.       end;
  817.       xbuf := xbuf + chr(lo(chk));
  818.    end;
  819.  
  820. (****************************************************************************)
  821. (*                        GET REMOTE RESPONSE                               *)
  822. (****************************************************************************)
  823.    procedure
  824.       get_response(var resp : char);
  825.    var
  826.       cnt          : integer;
  827.       answer_back  : string[10];
  828.    begin
  829.       cnt := 0;
  830.       repeat
  831.          recv_data(answer_back,1);
  832.          cnt := cnt + 1;
  833.       until ( cnt = 3 ) or ( answer_back <> '' );
  834.       if ( answer_back[1] = CAN ) or ( answer_back = '' ) then begin
  835.          continue_transfer := false;
  836.          resp := CAN;
  837.       end
  838.       else
  839.          resp := answer_back[1];
  840.    end;
  841.  
  842. (****************************************************************************)
  843. (*                            TRANSMIT FILE                                 *)
  844. (****************************************************************************)
  845.    procedure
  846.       transmit_file;
  847.    var
  848.       buf          : strtype;
  849.       response     : char;
  850.       cnt          : integer;
  851.       last_block   : boolean;
  852.    begin
  853.       error_count := 0;
  854.       mkwin(15,4,62,13,'Transmit XMODEM');
  855.       repeat
  856.          write(' Enter Filename to Transmit: ');
  857.          readln(filename);
  858.          if length(filename)=0 then begin
  859.             rmwin;
  860.             exit;
  861.          end;
  862.          assign(xmit_file,filename);
  863.          {$I-}
  864.          reset(xmit_file);
  865.          {$I+}
  866.          ok := (ioresult = 0);
  867.          if not ok then
  868.             writeln(' Cannot find file: ',filename);
  869.       until ok;
  870.       setserial(baud,stopbits,8,0);
  871.       writeln(' Files Size is ',filesize(xmit_file)+1,' Blocks.');
  872.       xmodem_buf_cnt := 0;
  873.       block_count := 1;
  874.       build_xmodem_buffer(buf,last_block);
  875.       continue_transfer := true;
  876.       start_time := time;
  877.       xmit_data('Holding for start of transfer...'+CRLF);
  878.       writeln(' Waiting for start... ');
  879.       writeln;
  880.       get_response(response);
  881.       if response <> CAN then begin
  882.          sync_with_remote;
  883.          xmit_data(buf);
  884.          get_response(response);
  885.          gotoxy(1,3);
  886.          display_headings;
  887.          display_counts( 6 );
  888.       end;
  889.       while ( response <> EOT )
  890.         and ( response <> CAN )
  891.         and ( continue_transfer )
  892.       do begin
  893.          sync_with_remote;
  894.          case response of
  895.             NAK : begin
  896.                      error_count := error_count + 1;
  897.                      if error_count > 30 then
  898.                         ask_operator(response);
  899.                      sync_NAK;
  900.                      if continue_transfer then begin
  901.                         xmit_data(buf);
  902.                         get_response(response);
  903.                      end;
  904.                   end;
  905.             ACK : begin
  906.                      if last_block then
  907.                         response := EOT
  908.                      else begin
  909.                         block_count := block_count + 1;
  910.                         build_xmodem_buffer(buf,last_block);
  911.                         xmit_data(buf);
  912.                         get_response(response);
  913.                      end;
  914.                   end;
  915.          else
  916.             response := NAK;
  917.             error_count := error_count + 1;
  918.          end;
  919.          display_counts( 6 );
  920.       end;
  921.       sync_with_remote;
  922.       if not continue_transfer then begin
  923.          store_sout_buffer( CAN );
  924.          response := CAN;
  925.       end
  926.       else begin
  927.          cnt := 0;
  928.          repeat
  929.             store_sout_buffer( EOT );
  930.             get_response(response);
  931.             cnt := cnt + 1;
  932.          until ( response = ACK ) or ( response = CAN ) or ( cnt = 5 );
  933.       end;
  934.       close(xmit_file);
  935.       setserial(baud,stopbits,databits,par);
  936.       if response = CAN then
  937.          writeln(' File transfer canceled!')
  938.       else
  939.          writeln(' File transmission complete.');
  940.       wait_for_key;
  941.       rmwin;
  942.    end;
  943.  
  944. (****************************************************************************)
  945. (*                                H E L P                                   *)
  946. (****************************************************************************)
  947.    procedure
  948.       give_help;
  949.    begin
  950.       mkwin(31,1,75,24,'Commands, with ALT');
  951.       writeln;
  952.       writeln('    T = Terminate and return to DOS.');
  953.       writeln('    R = Receive using XMODEM protocol.');
  954.       writeln('    X = Transmit using XMODEM protocol.');
  955.       writeln('    A = Transmit using ASCII XON/XOFF.');
  956.       writeln('    C = Toggle capture mode ON/OFF.');
  957.       writeln('    L = Display the disk directory.');
  958.       writeln('    N = New directory and/or drive.');
  959.       writeln('    V = View file.   K = Kill file.');
  960.       writeln('    Y = Copy file.   M = Macro key defs.');
  961.       writeln('    H = Help menu.   I = Change config.');
  962.       writeln('    U = Used time.   F = Fix time.');
  963.       writeln('    S = Change communication parameters.');
  964.       writeln('    D = Modem and dialing management.');
  965.       writeln('    O = Order the dialing directory.');
  966.       writeln('    G = Redial the last number.');
  967.       writeln('    E = Toggle between FULL/HALF duplex.');
  968.       writeln('    Q = Hang up.  ^PrtSc = Toggle printer.');
  969.       writeln('    W = Wipe the screen, clear it.');
  970.       writeln('    P = Put a nickel in the jukebox.');
  971.       writeln;
  972.       wait_for_key;
  973.       rmwin;
  974.    end;
  975.  
  976. (****************************************************************************)
  977. (*                       RECONFIGURE SYSTEM DEFAULTS                        *)
  978. (****************************************************************************)
  979.    procedure
  980.       change_default( k : integer );
  981.    begin
  982.       gotoxy(29,k+1);
  983.       case k of
  984.          1 : num_input(default_stopbits);
  985.          2 : num_input(default_databits);
  986.          3 : begin
  987.                 str_input(parity_ch);
  988.                 parity_ch := upcase( parity_ch[1] );
  989.                 case parity_ch of
  990.                    'N' : default_parity := 0;
  991.                    'E' : default_parity := 1;
  992.                    'O' : default_parity := 2;
  993.                 end;
  994.              end;
  995.          4 : num_input(default_baud);
  996.          5 : num_input(wait_increment);
  997.          6 : str_input(dial_pre_str);
  998.          7 : str_input(dial_post_str);
  999.          8 : str_input(modem_init_str);
  1000.          9 : str_input(speaker_on);
  1001.         10 : str_input(speaker_off);
  1002.         11 : num_input(redial_time);
  1003.         12 : str_input(forced_carrier);
  1004.         13 : num_input(carrier_timeout);
  1005.         14 : begin
  1006.                 str_input(dial_PATH);
  1007.                 if dial_PATH[length(dial_PATH)] <> '\' then
  1008.                    dial_PATH := dial_PATH + '\';
  1009.              end;
  1010.         15 : num_input(XON);
  1011.         16 : num_input(XOFF);
  1012.         17 : str_input(vt100_mode);
  1013.       end;
  1014.    end;
  1015.  
  1016.    procedure
  1017.       reconfigure_defaults;
  1018.    var
  1019.       i   : integer;
  1020.       ds  : string10;
  1021.       chg : boolean;
  1022.    begin
  1023.       chg := false;
  1024.       mkwin(6,2,75,23,'Reconfigure.  Use: | for CR, ~ for delay.');
  1025.       writeln;
  1026.       writeln('  1. Number of Stopbits ... ',default_stopbits);
  1027.       writeln('  2. Number of Databits ... ',default_databits);
  1028.       write  ('  3. Parity Type .......... ');
  1029.       case default_parity of
  1030.          0 : parity_ch := 'N';
  1031.          1 : parity_ch := 'E';
  1032.          2 : parity_ch := 'O';
  1033.       end;
  1034.       writeln(parity_ch);
  1035.       writeln('  4. Baud Rate ............ ',default_baud);
  1036.       writeln('  5. Time Base ............ ',wait_increment);
  1037.       writeln('  6. Dial Pre-String ...... ',dial_pre_str);
  1038.       writeln('  7. Dial Post-String ..... ',dial_post_str);
  1039.       writeln('  8. Modem Init String .... ',modem_init_str);
  1040.       writeln('  9. Speaker-On String .... ',speaker_on);
  1041.       writeln(' 10. Speaker-Off String ... ',speaker_off);
  1042.       writeln(' 11. Time Until Redial .... ',redial_time);
  1043.       writeln(' 12. Forced Carrier ....... ',forced_carrier);
  1044.       writeln(' 13. Carrier Timeout ...... ',carrier_timeout);
  1045.       writeln(' 14. Directory PATH ....... ',dial_PATH);
  1046.       writeln(' 15. XON char, decimal .... ',XON);
  1047.       writeln(' 16. XOFF char, decimal ... ',XOFF);
  1048.       writeln(' 17. VT100 Mode ........... ',vt100_mode);
  1049.       writeln;
  1050.       write  (' Enter the number to change or RETURN to exit: ');
  1051.       repeat
  1052.          gotoxy(48,20);
  1053.          clreol;
  1054.          read(ds);
  1055.          i:=bval(ds+' ');
  1056.          if i in [ 1..17 ] then begin
  1057.             chg := true;
  1058.             change_default(i);
  1059.          end
  1060.          else
  1061.             i:=0;
  1062.       until i=0;
  1063.       if chg then begin
  1064.          upstring(forced_carrier);
  1065.          upstring(dial_PATH);
  1066.          upstring(speaker_on);
  1067.          upstring(speaker_off);
  1068.          upstring(dial_pre_str);
  1069.          upstring(dial_post_str);
  1070.          upstring(modem_init_str);
  1071.          upstring(vt100_mode);
  1072.          assign(textfile,cnf_PATH+'TMODEM.CNF');
  1073.          rewrite_config_file;
  1074.          close(textfile);
  1075.       end;
  1076.       if vt100_mode[1]='T' then silent_mode:=true;
  1077.       rmwin;
  1078.    end;